using System;
using System.Threading;
using System.Collections;

namespace Lutos.Spider
{
    public sealed class MutiThreadingFlow
    {
        public delegate IEnumerable ProcessHandler(object task);
        public MutiThreadingFlow(ProcessHandler processor, Queue prevs, Queue nexts, int threadsCount)
            : this(processor, prevs, nexts, threadsCount, 100)
        { }
        public MutiThreadingFlow(ProcessHandler processor, Queue prevs, Queue nexts, int threadsCount, int sleepMS)
        {
			if (processor == null || prevs == null)
			{
				throw new ArgumentNullException();
			}
            this.Prevs = prevs;
            this.Nexts = nexts;
            this.Processor = processor;
            this.sleepMS = sleepMS;
            this.ts = new Thread[threadsCount];
        }
        public readonly ProcessHandler Processor;
        public readonly Queue Prevs;
        public readonly Queue Nexts;
        int sleepMS;
        Thread[] ts;
        int state = -1;
        private void run()
        {
            object p = null;
            while (state != 0)
            {
                lock (Prevs)
                {
                    if (Prevs.Count == 0)
                    {
                        Thread.Sleep(sleepMS);
                        continue;
                    }
                    p = Prevs.Dequeue();
                }
                IEnumerable n = this.Processor(p);
				if(this.Nexts != null)
				lock (Nexts)
				{
					foreach(object o in n)
						Nexts.Enqueue(o);
				}
			}
        }
        public void Start()
        {
            if (Interlocked.CompareExchange(ref this.state, 1, -1) < 0)
            {
                for(int i=ts.Length-1; i>=0; i--)
                    (ts[i] = new Thread(new ThreadStart(this.run))).Start();
            }
        }
        public void Stop()
        {
            Interlocked.CompareExchange(ref this.state, 0, 1);
        }

        public bool IsAlive
        {
            get
			{
				foreach (Thread t in ts)
				{
					if (t.IsAlive) 
					{
						return true;
					}
				}
                return false;
            }
        }
    }
}
